package com.dolphin.common.expr;

import com.alibaba.fastjson.annotation.JSONField;
import com.dolphin.common.component.var.enums.ValueTypeEnum;
import com.dolphin.common.expr.emus.ConditionNodeTypeEnum;
import com.dolphin.common.expr.emus.ExecutionRelationEnum;
import com.dolphin.common.expr.emus.OperateTypeEnum;
import com.google.common.collect.Lists;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.googlecode.aviator.exception.ExpressionSyntaxErrorException;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.List;

/**
 * @author shida
 */
@Getter
@Setter
@ToString
@Slf4j
public class Condition {

    /**
     * 节点类型
     */
    private ConditionNodeTypeEnum nodeType;

    /**
     * 操作符
     */
    private OperateTypeEnum operateType;

    /**
     * 被操作字典
     * 条件字典标识，nodeType为item时有值
     */
    private String varCode;
    /**
     * 被操作变量
     * 条件变量标识，nodeType为item时有值
     */
    private String varName;
    /**
     * 被操作变量
     * 条件变量标识，nodeType为item时有值
     */
    private String varBid;
    /**
     * 标志value是否是变量bid还是具体数值
     * false：表示变量，true：表示具体数值
     */
    private boolean flag;

    /**
     * 参考字段，条件字段的bid
     */
    private String varBidValue;

    /**
     * 参考值
     */
    private String value;

    private ValueTypeEnum valueType;

    /**
     * 子节点，nodeType为group时有值
     */
    private ExecutionRelationEnum relation;

    private List<Condition> children = Lists.newArrayList();

    /**
     * 节点在兄弟节点中的顺序
     */
    private int order;

    /**
     * 下面是内部变量，不对外开发get/set方法
     */
    @JSONField(serialize = false)
    private Expression expression;

    @JSONField(serialize = false)
    private String expressionStr;

    @JSONField(serialize = false)
    private List<String> varBids;

    public Expression fetchExpression() {
        if(StringUtils.isEmpty(fetchExpressionStr()) == true){
            return null;
        }

        if(expression == null){
            try {
                expression = AviatorEvaluator.compile(fetchExpressionStr(), true);
            }catch (ExpressionSyntaxErrorException ex){
                log.error("compile error, exp=" + fetchExpressionStr(), ex);
            }
        }

        return expression;
    }

    public String fetchExpressionStr() {
        if(StringUtils.isEmpty(expressionStr)){
            expressionStr = AviatorExpressionGenerator.genExpression(this);
        }

        return expressionStr;
    }

    public List<String> fetchVarBids(){
        Expression expression = fetchExpression();
        if(expression == null){
            return Collections.emptyList();
        }
        if(varBids == null){
            varBids = fetchExpression().getVariableNames();
        }
        if(varBids != null && varBids.size() > 0){
            //AviatorEvaluator.compile在编译的时候会把nil带进来，需要手动移除
            varBids.removeIf("nil"::equalsIgnoreCase);
        }

        return varBids;
    }

    public ConditionNodeTypeEnum getNodeType() {
        return nodeType;
    }

    public void setNodeType(ConditionNodeTypeEnum nodeType) {
        this.nodeType = nodeType;
    }

    public OperateTypeEnum getOperateType() {
        return operateType;
    }

    public void setOperateType(OperateTypeEnum operateType) {
        this.operateType = operateType;
    }

    public String getVarCode() {
        return varCode;
    }

    public void setVarCode(String varCode) {
        this.varCode = varCode;
    }

    public String getVarName() {
        return varName;
    }

    public void setVarName(String varName) {
        this.varName = varName;
    }

    public String getVarBid() {
        return varBid;
    }

    public void setVarBid(String varBid) {
        this.varBid = varBid;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public String getVarBidValue() {
        return varBidValue;
    }

    public void setVarBidValue(String varBidValue) {
        this.varBidValue = varBidValue;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public ValueTypeEnum getValueType() {
        return valueType;
    }

    public void setValueType(ValueTypeEnum valueType) {
        this.valueType = valueType;
    }

    public ExecutionRelationEnum getRelation() {
        return relation;
    }

    public void setRelation(ExecutionRelationEnum relation) {
        this.relation = relation;
    }

    public List<Condition> getChildren() {
        return children;
    }

    public void setChildren(List<Condition> children) {
        this.children = children;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
}
